<template>
  <AxiomLayout :columns="layoutConfig" style="height: calc(100vh - 120px)">
    <template #col-tree>
      <div
        class="p-3 h-100 overflow-y-auto"
        @dragover.prevent
        @drop="handleDropOnTree($event)"
      >
        <AxiomTree
          :key="treeKey"
          :data="folderTree"
          node-key="id"
          :props="{ label: 'name', children: 'children' }"
          :action-menu-items="folderActionMenuItems"
          :default-expanded-keys="expandedKeys"
          @action-command="handleFolderCommand"
          @node-renamed="handleFolderRenamed"
          @node-click="handleFolderClick"
          @node-drag-start="handleNodeDragStart"
          @node-expand="handleNodeExpand"
          @node-collapse="handleNodeCollapse"
          :allow-drop="allowDrop"
          show-actions
          draggable
          highlight-current
        />
      </div>
    </template>
    <template #col-main>
      <div class="d-flex flex-column h-100 p-3">
        <AxiomToolbar>
          <AxiomButton icon="upload" @click="handleUpload">上传文件</AxiomButton>
          <input type="file" ref="fileInputRef" @change="onFileSelected" class="d-none" multiple />
          <AxiomButton icon="Plus" @click="handleCreateFolder">新建文件夹</AxiomButton>
        </AxiomToolbar>

        <AxiomPCBreadcrumb :items="breadcrumbs" @item-click="handleBreadcrumbClick" bordered class="mb-3" />

        <AxiomToolbar class="mb-3">
          <AxiomInput
            v-model="searchQuery"
            placeholder="在当前文件夹下搜索..."
            @keydown.enter="handleSearch"
            clearable
            @clear="handleSearch"
          />
          <AxiomButton type="primary" icon="search" @click="handleSearch">搜索</AxiomButton>
        </AxiomToolbar>

        <AxiomDataTable
          :data="fileList"
          :columns="columns"
          class="flex-1"
          row-key="id"
          @row-drag-start="handleRowDragStart"
          @row-drag-over="handleRowDragOver"
          @row-drag-drop="handleRowDrop"
          :pagination="pagination"
          @page-change="handlePageChange"
          @size-change="handleSizeChange"
        >
          <!-- Custom column for file type icon -->
          <template #column-name="{ row }">
            <AxiomGroup align="center" gap="small">
              <AxiomIcon :name="row.is_dir ? 'folder' : 'document'" />
              <AxiomInput
                  v-if="editingId === row.id"
                  v-model="editingName"
                  @keydown.enter="saveRename(row)"
                  @keydown.esc="cancelRename"
                  @blur="cancelRename"
                  autofocus
                  size="small"
              />
              <span v-else>{{ row.name }}</span>
            </AxiomGroup>
          </template>
          <!-- Custom column for file type -->
          <template #column-mime_type="{ row }">
              {{ row.is_dir ? '文件夹' : row.mime_type }}
          </template>
          <!-- Custom column for file size -->
          <template #column-size_bytes="{ row }">
            {{ row.is_dir ? '-' : formatSize(row.size_bytes) }}
          </template>
          <!-- Custom column for actions -->
          <template #column-actions="{ row }">
              <AxiomButton type="primary" text @click="handleRename(row)">重命名</AxiomButton>
              <AxiomButton type="primary" text @click="handleDownload(row)">下载</AxiomButton>
              <AxiomButton type="danger" text @click="handleDeleteRow(row)">删除</AxiomButton>
          </template>
        </AxiomDataTable>
      </div>

      <AxiomDialog v-model="createFolderDialogVisible" title="新建文件夹" @confirm="confirmCreateFolder">
        <AxiomForm ref="createFolderFormRef" :model="newFolder" @submit.prevent>
            <AxiomFormItem label="文件夹名称" prop="name" :rules="{ required: true, message: '请输入文件夹名称' }">
                <AxiomInput v-model="newFolder.name" @keydown.enter="confirmCreateFolder"/>
            </AxiomFormItem>
        </AxiomForm>
      </AxiomDialog>
    </template>
  </AxiomLayout>
</template>

<script setup>
import { ref, watch, inject, nextTick } from 'vue';
import {
  AxiomGroup,
  AxiomTree,
  AxiomToolbar,
  AxiomButton,
  AxiomDataTable,
  AxiomIcon,
  AxiomDialog,
  AxiomForm,
  AxiomFormItem,
  AxiomInput,
  AxiomPCBreadcrumb,
  AxiomLayout,
} from 'axiom-view';
import { fileStorageApi } from '@/api/knowledge/file.js';

const layoutConfig = ref([
  { id: 'tree', width: '250px' },
  { id: 'main', width: '1fr' },
]);

const props = defineProps({
  bucket: {
    type: Object,
    required: true,
  },
});

const { notification, useConfirm } = inject('axiom-utils');
const { show: showConfirm } = useConfirm;

const folderTree = ref([]);
const fileList = ref([]);
const currentFolderId = ref(null);
const breadcrumbs = ref([]);
const treeKey = ref(0);
const expandedKeys = ref([]);

// 文件夹树相关
const folderActionMenuItems = [
    { label: '重命名', command: 'rename', icon: 'Edit' },
    { label: '删除', command: 'delete', icon: 'Delete', divided: true },
];

// Drag and Drop state
const draggedItems = ref([]);
const searchQuery = ref('');

// Pagination state
const pagination = ref({
    currentPage: 1,
    pageSize: 20,
    total: 0,
});

// Refs for inline editing
const editingId = ref(null);
const editingName = ref('');

// Refs for create folder dialog
const createFolderDialogVisible = ref(false);
const createFolderFormRef = ref(null);
const newFolder = ref({ name: '' });

// Ref for file input
const fileInputRef = ref(null);

const columns = [
  { prop: 'name', label: '名称', slot: 'column-name' },
  { prop: 'mime_type', label: '类型', width: 150, slot: 'column-mime_type' },
  { prop: 'update_time', label: '修改日期', width: 180 },
  { prop: 'size_bytes', label: '大小', width: 120, slot: 'column-size_bytes' },
  { prop: 'actions', label: '操作', width: 220, slot: 'column-actions' },
];

// --- Drag and Drop Handlers ---

function handleNodeDragStart(node, event) {
    // Dragging from the tree
    event.dataTransfer.effectAllowed = 'move';
    draggedItems.value = [{ id: node.data.id, is_dir: true }];
    event.dataTransfer.setData('application/json', JSON.stringify(draggedItems.value));
}

function handleRowDragStart(row, event) {
    // Dragging from the table
    event.dataTransfer.effectAllowed = 'move';
    draggedItems.value = [{ id: row.id, is_dir: row.is_dir }];
    event.dataTransfer.setData('application/json', JSON.stringify(draggedItems.value));
}

function handleRowDragOver(row, event) {
    // Allow dropping only on folders
    if (row.is_dir) {
        event.preventDefault();
    }
}

function allowDrop(draggingNode, dropNode, type) {
    // Allow dropping only 'into' a folder, not before or after
    return dropNode.data.is_dir && type === 'inner';
}

function handleDropOnTree(event) {
    // This handles drops on the tree container, assuming it's a drop into the root
    const targetFolderId = null; // Root
    handleDrop(event, targetFolderId);
}

function handleRowDrop(row, event) {
    // This handles drops on a folder row within the DataTable
    if (row.is_dir) {
        handleDrop(event, row.id);
    }
}

async function handleDrop(event, targetFolderId) {
    event.preventDefault();
    const itemsToMove = JSON.parse(event.dataTransfer.getData('application/json'));
    const itemIds = itemsToMove.map(item => item.id);

    // Prevent dropping a folder into itself or its children (simple check)
    if (itemIds.includes(targetFolderId)) {
        notification.warning({ title: '操作无效', message: '不能将文件夹移动到其自身内部' });
        return;
    }

    try {
        await fileStorageApi.move(itemIds, targetFolderId);
        notification.success({ title: '成功', message: '移动成功' });
        await fetchFolderTree();
        await fetchFileList(currentFolderId.value);
    } catch (error) {
        console.error('Failed to move items:', error);
    } finally {
        draggedItems.value = [];
    }
}

function handleNodeExpand(data) {
    if (!expandedKeys.value.includes(data.id)) {
        expandedKeys.value.push(data.id);
    }
}

function handleNodeCollapse(data) {
    const index = expandedKeys.value.indexOf(data.id);
    if (index > -1) {
        expandedKeys.value.splice(index, 1);
    }
}


// --- Core Data Fetching ---

function addIsDirToTree(nodes) {
    if (!nodes) return [];
    return nodes.map(node => ({
        ...node,
        is_dir: true,
        children: addIsDirToTree(node.children || []),
    }));
}

async function fetchFolderTree() {
  try {
    const res = await fileStorageApi.getTree({ bucket: props.bucket.bucket_name });
    folderTree.value = addIsDirToTree(res.data || []);
    // Initially build breadcrumbs for root
    buildBreadcrumbs(null);
  } catch (error) {
    console.error(error);
  }
}

async function fetchFileList(folderId) {
  try {
    currentFolderId.value = folderId;
    buildBreadcrumbs(folderId);

    const params = {
        bucket: props.bucket.bucket_name,
        parent_id: folderId,
        is_dir: 0, // Only fetch files
        page: pagination.value.currentPage,
        page_size: pagination.value.pageSize,
    };
    if (searchQuery.value) {
        params.name = searchQuery.value;
    }

    const res = await fileStorageApi.getItems(params);
    fileList.value = res.data.items || [];
    pagination.value.total = res.data.total || 0;
  } catch (error) {
    console.error(error);
  }
}

function handlePageChange(newPage) {
    pagination.value.currentPage = newPage;
    fetchFileList(currentFolderId.value);
}

function handleSizeChange(newSize) {
    pagination.value.pageSize = newSize;
    pagination.value.currentPage = 1; // Reset to first page
    fetchFileList(currentFolderId.value);
}

function handleSearch() {
    pagination.value.currentPage = 1; // Reset to first page on new search
    fetchFileList(currentFolderId.value);
}

function findPath(tree, nodeId, path = []) {
    for (const node of tree) {
        const currentPath = [...path, { text: node.name, to: { id: node.id } }];
        if (node.id === nodeId) {
            return currentPath;
        }
        if (node.children) {
            const result = findPath(node.children, nodeId, currentPath);
            if (result) {
                return result;
            }
        }
    }
    return null;
}

function buildBreadcrumbs(folderId) {
    const root = { text: '根目录', to: { id: null } };
    if (!folderId) {
        breadcrumbs.value = [root];
        return;
    }

    const path = findPath(folderTree.value, folderId);
    if (path) {
        breadcrumbs.value = [root, ...path];
    } else {
        // If folder is not in the tree (e.g. deep link), show at least root and current
        // Find the name from the fileList if possible
        const currentFolder = fileList.value.find(f => f.id === folderId);
        const name = currentFolder ? currentFolder.name : '当前文件夹';
        breadcrumbs.value = [root, {text: name, to: { id: folderId }, disabled: true }]
    }
}

function handleBreadcrumbClick(item) {
    pagination.value.currentPage = 1;
    fetchFileList(item.to.id);
}

function handleFolderClick(folder) {
  pagination.value.currentPage = 1;
  fetchFileList(folder.id);
}

function handleFolderCommand(command, folder) {
    if (command === 'delete') {
        handleDeleteRow(folder);
    }
    // 'rename' command is now handled internally by AxiomTree component
}

async function handleFolderRenamed({ nodeId, newName }) {
    try {
        await fileStorageApi.rename(nodeId, newName);
        notification.success({ title: '成功', message: '重命名成功' });
        
        // 刷新文件列表和父文件夹
        await fetchFolderTree();
        if (currentFolderId.value === nodeId || fileList.value.some(f => f.parent_id === nodeId)) {
            await fetchFileList(currentFolderId.value);
        }
    } catch (error) {
        console.error(error);
    }
}

function goToRoot() {
    fetchFileList(null);
}

function handleRename(row) {
    editingId.value = row.id;
    editingName.value = row.name;
}

async function saveRename(row) {
    if (!editingId.value || editingName.value === row.name) {
        cancelRename();
        return;
    }
    
    try {
        await fileStorageApi.rename(editingId.value, editingName.value);
        notification.success({ title: '成功', message: '重命名成功' });
        await fetchFileList(currentFolderId.value);
        if (row.is_dir) {
            await fetchFolderTree();
        }
    } catch (error) {
        console.error(error);
    } finally {
        cancelRename();
    }
}

function cancelRename() {
    editingId.value = null;
    editingName.value = '';
}

function handleUpload() {
  if (fileInputRef.value) {
    fileInputRef.value.click();
  }
}

async function onFileSelected(event) {
    const files = event.target.files;
    if (!files || files.length === 0) return;

    const formData = new FormData();
    formData.append('bucket', props.bucket.bucket_name);
    if (currentFolderId.value) {
        formData.append('parent_id', currentFolderId.value);
    }

    for (const file of files) {
        formData.append('files', file);
    }
    
    const toastMessage = files.length > 1 ? `正在上传 ${files.length} 个文件...` : '正在上传文件...';
    let uploadToast = null;
    try {
        uploadToast = notification.info({ title: '上传中', message: toastMessage, duration: 0 });
        await fileStorageApi.upload(formData);
        notification.success({ title: '成功', message: `成功上传 ${files.length} 个文件` });
        searchQuery.value = ''; // Clear search after upload
        await fetchFileList(currentFolderId.value);
    } catch (error) {
        console.error(error);
    } finally {
        if (uploadToast && typeof uploadToast.close === 'function') {
            uploadToast.close();
        }
        // Reset the input so the user can select the same file(s) again.
        if (event.target) {
            event.target.value = '';
        }
    }
}

function handleCreateFolder() {
  newFolder.value.name = '';
  createFolderDialogVisible.value = true;
}

async function confirmCreateFolder() {
    const isValid = await createFolderFormRef.value.validate();
    if (!isValid) return;

    try {
        const res = await fileStorageApi.createFolder({
            bucket: props.bucket.bucket_name,
            name: newFolder.value.name,
            parent_id: currentFolderId.value,
        });
        
        notification.success({ title: '成功', message: '文件夹创建成功' });
        createFolderDialogVisible.value = false;

        // [最终方案] 本地更新 + key 强制刷新
        if (res.data && res.data.length > 0) {
            const newFolderData = {
                ...res.data[0],
                is_dir: true, 
                children: res.data[0].children || [],
            };

            const findAndAdd = (nodes, parentId, itemToAdd) => {
                if (!parentId) {
                    nodes.push(itemToAdd);
                    return true;
                }
                for (const node of nodes) {
                    if (node.id === parentId) {
                        if (!node.children) {
                            node.children = [];
                        }
                        node.children.push(itemToAdd);
                        return true;
                    }
                    if (node.children && findAndAdd(node.children, parentId, itemToAdd)) {
                        return true;
                    }
                }
                return false;
            };

            findAndAdd(folderTree.value, currentFolderId.value, newFolderData);
            treeKey.value++; // 强制刷新
        }
        
        await fetchFileList(currentFolderId.value);
    } catch (error) {
        console.error(error);
    }
}

async function handleDownload(row) {
    if (row.is_dir) {
        notification.warning({ title: '操作无效', message: '文件夹不支持下载' });
        return;
    }
    
    const downloadToast = notification.info({ title: '下载中', message: `正在准备下载: ${row.name}...`, duration: 0 });
    try {
        const result = await fileStorageApi.download(row.id);

        if (result.type === 'url') {
            // S3 file: open the presigned URL directly.
            window.open(result.data, '_blank');
        } else if (result.type === 'blob') {
            // Local file: create a blob URL and trigger download.
            const blob = result.data; // The data itself is the blob
            
            let filename = row.name; // Use the name from the row data
            
            const link = document.createElement('a');
            link.href = window.URL.createObjectURL(blob);
            link.download = filename;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            window.URL.revokeObjectURL(link.href);
        }
    } catch (error) {
        console.error('Download failed:', error);
    } finally {
        // Since toast.info does not return a closable instance,
        // we can't programmatically close it. A success/error toast is enough.
    }
}

async function handleDeleteRow(row) {
    const confirmed = await showConfirm({
        title: '确认删除',
        content: `您确定要删除项目 “${row.name}” 吗？此操作不可逆。`,
    });

    if (confirmed) {
        try {
            await fileStorageApi.delete(row.id);
            notification.success({ title: '成功', message: '删除成功' });
            await fetchFileList(currentFolderId.value);
            await fetchFolderTree();
        } catch (error) {
            console.error(error);
        }
    }
}

function formatSize(bytes) {
  if (bytes === 0) return '0 Bytes';
  const k = 1024;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}


// Fetch data when the bucket changes
watch(() => props.bucket, () => {
  fetchFolderTree();
  fetchFileList(null);
}, { immediate: true });

defineExpose({
    goToRoot,
});
</script>

<style scoped lang="scss">
/* This component is now free of local styles. All styling is handled by the AxiomView framework. */
</style> 